package abg.core.service.mt.impl;

import abg.core.common.cache.Cache;
import abg.core.common.cache.CacheKey;
import abg.core.common.message.RedisMsgKit;
import abg.core.common.message.RedisMsgType;
import abg.core.common.security.AuthKit;
import abg.core.common.security.AuthUser;
import abg.core.common.util.*;
import abg.core.common.util.password.PWD;
import abg.core.common.util.valid.Length;
import abg.core.common.util.valid.NotBlank;
import abg.core.common.util.valid.base.Valid;
import abg.core.domain.db.*;
import abg.core.domain.search.Psh;
import abg.core.domain.sys.MSG;
import abg.core.domain.sys.SRS;
import abg.core.domain.sys.ServiceException;
import abg.core.domain.ws.WsPushType;
import abg.core.mapper.*;
import abg.core.service.mt.MtLiveRoomService;
import abg.core.common.ws.handler.TextHandler;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

import static abg.core.domain.db.table.MtRoomInOutTableDef.MT_ROOM_IN_OUT;
import static abg.core.domain.db.table.MtRoomUserAuthTableDef.MT_ROOM_USER_AUTH;
import static abg.core.domain.db.table.SysUserTableDef.SYS_USER;

/**
 * 会议室内部逻辑
 */
@Service
public class MtLiveRoomServiceImpl implements MtLiveRoomService {
    @Resource
    private Cache<String> cache;

    @Resource
    private MtRoomUserAuthMapper roomUserAuthMapper;

    @Resource
    private MtRoomMapper mtRoomMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private MtRoomMsgMapper mtRoomMsgMapper;

    @Resource
    private MtRoomInOutMapper inOutMapper;

    @Override
    public Page<MtRoomUserAuth> roomUserPage(String mtId, String key, String type, Psh psh) {
        AuthUser authUser = AuthKit.mastLogin();
        MtRoomUserAuth mtRoomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, authUser.getUserId());

        QueryWrapper wrapper = QueryWrapper.create().select(MT_ROOM_USER_AUTH.ALL_COLUMNS, SYS_USER.PHONE)
                .from(MT_ROOM_USER_AUTH).leftJoin(SYS_USER).on(MT_ROOM_USER_AUTH.USER_ID.eq(SYS_USER.ID))
                .and(MT_ROOM_USER_AUTH.MT_ID.eq(mtId))
                //关联搜索用户条件/关联搜索昵称
                .and(
                        SYS_USER.ACCOUNT.like(key).or(SYS_USER.PHONE.like(key)).or(SYS_USER.ID_CARD_NAME.like(key)).or(MT_ROOM_USER_AUTH.MT_NICK_NAME.like(key))
                );

        //查展示用户，只查询此刻正在会议内的人员
        if ("liveHomeUser".equals(type)) {
            wrapper
                    .and(MT_ROOM_USER_AUTH.IS_IN_ROOM.eq("1")) //在房间内
                    .orderBy(MT_ROOM_USER_AUTH.IS_COMPERE.desc(), MT_ROOM_USER_AUTH.AUTH_TOP.desc());
        }
        //查管理，不需要查房主
        else {
            wrapper.and(MT_ROOM_USER_AUTH.USER_ID.ne(mtRoomUserAuth.getUserId()));
        }
        return roomUserAuthMapper.paginate(psh, wrapper);
    }

    //申请连麦分页数据
    @Override
    public Page<MtRoomUserAuth> applyTopPage(String mtId, String key, Psh psh) {
        mastMtCompere(mtId);

        QueryWrapper wrapper = QueryWrapper.create().select(MT_ROOM_USER_AUTH.ALL_COLUMNS, SYS_USER.PHONE)//
                .from(MT_ROOM_USER_AUTH).leftJoin(SYS_USER).on(MT_ROOM_USER_AUTH.USER_ID.eq(SYS_USER.ID))//
                .and(MT_ROOM_USER_AUTH.MT_ID.eq(mtId)).and(MT_ROOM_USER_AUTH.IS_COMPERE.eq("0"))//
                .and(MT_ROOM_USER_AUTH.APPLY_TOP_STATUS.eq("1"))//已发起申请
                //关联条件、昵称、账号、手机号、身份证姓名
                .and(
                        SYS_USER.ACCOUNT.like(key).or(SYS_USER.PHONE.like(key)).or(SYS_USER.ID_CARD_NAME.like(key)).or(MT_ROOM_USER_AUTH.MT_NICK_NAME.like(key))
                );

        return roomUserAuthMapper.paginate(psh, wrapper);
    }

    //进出会议消息
    @Override
    public void liveRoomSendInOutMsg(String mtId, String type) {
        AuthUser authUser = AuthKit.mastLogin();
        String msg = "进入会议";
        String isInRoom = "0";
        if ("1".equals(type)) {
            msg = "进入会议";
            isInRoom = "1";
        }
        if ("2".equals(type)) {
            msg = "离开会议";
            isInRoom = "0";
        }
        if ("3".equals(type)) {
            msg = "回到会议";
//            isInRoom = "1";
        }
        if ("4".equals(type)) {
            msg = "暂时离开会议";
//            isInRoom = "0";
        }

        wsMtRoomMsg(mtId, authUser.getUserId(), msg, 2000);

        //修改自己是否在房间内的状态
        //通知房间有人进出
        if ("1".equals(type) || "2".equals(type)) {
            MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
            mtRoomUserAuth.setIsInRoom(isInRoom);
            roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, authUser.getUserId());
        }
        wsSearchRoomUser(mtId);
    }

    //会议内发消息
    @Override
    public void liveRoomSendMsg(String mtId, String msg, Integer time) {
        if (time == null) time = 0;

        AuthUser authUser = AuthKit.mastLogin();

        boolean mtCompere = isMtCompere(mtId);

        //非房主
        if (!mtCompere) {
            //是否全员禁言
            MtRoom mtRoom = mtRoomMapper.selectOneById(mtId);
            if ("1".equals(mtRoom.getMsgAuth())) throw new ServiceException(MSG.MT_MSG_ALL_DISABLE);

            //检查发消息权限
            MtRoomUserAuth roomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, authUser.getUserId());
            if (roomUserAuth == null || "0".equals(roomUserAuth.getAuthMsg()))
                throw new ServiceException(MSG.MT_MSG_DISABLE);
        }

        //TODO 敏感词汇检索

        //通知房间，有消息进入
        if (time <= 0 || time >= 9000) time = 9000;

        wsMtRoomMsg(mtId, authUser.getUserId(), msg.trim(), time);

    }

    //结束会议
    @Override
    public boolean closeMtRoom(String mtId) {
        AuthUser authUser = AuthKit.mastLogin();

        boolean isMtCompere = isMtCompere(mtId);
        //不是房主，直接退出，通知房间人员更新信息
        if (!isMtCompere) {
            saveOutLog(mtId, authUser.getUserId());
            return true;
        }

        if (StringKit.isBlank(mtId)) throw new ServiceException(MSG.PARAM_ER);
        MtRoomUserAuth mtRoomUserAuth = mastMtCompere(mtId);

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.where("user_id = ?", mtRoomUserAuth.getUserId());

        MtRoom mtRoom1 = new MtRoom();
        mtRoom1.setMeetingStatus("1");

        int i = mtRoomMapper.updateByQuery(mtRoom1, wrapper);

        //TODO 关闭推流连接

        //通知房间已经关闭
        wsMtRoomClose(mtId);
        return true;
    }

    @Override
    public void userInRoom(String mtId) {
        AuthKit.mastLogin();

        //热度加1
        mtRoomMapper.addHot(mtId, 1);

        //通知房间内人员，信息变动
        wsRefreshRoomInfo(mtId);
    }

    //当前房间信息
    @Override
    public MtRoom roomInfo(String mtId) {
        MtRoom mtRoom = mtRoomMapper.selectOneById(mtId);
        //当前实时人数
        mtRoom.setNowUserCount(roomUserAuthMapper.getRoomNowUserCount(mtId) + "");

        //
        MtRoomUserAuth mtRoomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, mtRoom.getUserId());
        mtRoom.setCompereName(mtRoomUserAuth.getMtNickName());

        return mtRoom;
    }

    //同意连麦
    @Override
    public boolean agreeTop(String userId, String mtId) {
        addBeforeCheckMaxTopUser(mtId);

        //必须是房主操作
        mastMtCompere(mtId);

        //生成流地址
        MtRoom mtRoom = mtRoomMapper.selectOneById(mtId);
        LocalDateTime closeSettingTime = mtRoom.getCloseSettingTime();
        LocalDateTime now = LocalDateTime.now();
        long liveSecond = LocalDateKit.subSecond(closeSettingTime, now);
        if (liveSecond <= 0) throw new ServiceException(MSG.USER_MT_NO_AUTH);

        //生成Token
        String rtmpUrl = createRtmpUrlAndSaveToken(mtId, userId, liveSecond);

        //更新权限和推拉流地址
        MtRoomUserAuth update = new MtRoomUserAuth();
        update.setAuthTop("1");
        update.setApplyTopStatus("0");
        update.setRtmpPushUrl(rtmpUrl);
        update.setRtmpPullUrl(rtmpUrl);

        roomUserAuthMapper.updateByMtIdUserId(update, mtId, userId);

        //通知用户上麦成功
        wsUserTopStatus(mtId, userId, "1");

        //通知所有人，有人上麦
        wsRefreshTopList(mtId);

        return true;
    }

    /**
     * 生成RtmpUrl
     *
     * @param mtId
     * @param userId
     * @param liveSecond
     * @return
     */
    @Override
    public String createRtmpUrlAndSaveToken(String mtId, String userId, Long liveSecond) {
        String token = PWD.createPwdByPlain(mtId + userId);

        String tokenKey = MathKit.getMD5(CacheKey.MT_TOKEN.key() + mtId + userId);

        cache.set(tokenKey, token, liveSecond);

        return "/live/mt" + mtId + "/user" + userId + "?token=" + tokenKey;
    }

    //检查Token
    @Override
    public boolean checkRtmpByCacheToken(String mtId, String userId, String tokenKey) {
        String token1 = cache.get(tokenKey);
        String token2 = cache.get(MathKit.getMD5(CacheKey.MT_TOKEN.key() + mtId + userId));

        if (StringKit.isBlank(token1) || StringKit.isBlank(token2) || !token1.equals(token2))
            throw new ServiceException(MSG.ER_403);

        boolean bool = PWD.checkPlainPwd((mtId + userId), token2);
        if (!bool) throw new ServiceException(MSG.ER_403);

        return false;
    }

    //强制用户下麦
    @Override
    public boolean outTop(String userId, String mtId) {
        boolean b = refuseTop(userId, mtId, true);

        if (b) {

            //通知用户下麦
            wsUserTopStatus(mtId, userId, "0");

            //通知所有人，有人下麦
            wsRefreshTopList(mtId);

        }

        return b;
    }

    //发起申请连麦
    @Override
    public boolean applyTop(String mtId) {
        AuthUser authUser = AuthKit.mastLogin();

        //查询是否存在
        MtRoomUserAuth mtRoomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, authUser.getUserId());

        //不存在直接插入，然后推送申请通知
        if (mtRoomUserAuth == null) {
            mtRoomUserAuth = new MtRoomUserAuth();
            mtRoomUserAuth.setUserId(authUser.getUserId());
            mtRoomUserAuth.setMtId(mtId);
            mtRoomUserAuth.setApplyTopStatus("1");
            roomUserAuthMapper.insertSelective(mtRoomUserAuth);
            wsApplyTopMsg(authUser.getUserId(), mtId);
            return true;
        }

        //如果没有资格，发起申请，发送消息
        String authTop = mtRoomUserAuth.getAuthTop();
        if ("0".equals(authTop)) {
            mtRoomUserAuth.setApplyTopStatus("1");
            roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, authUser.getUserId());
            wsApplyTopMsg(authUser.getUserId(), mtId);
            return true;
        } else {
            throw new ServiceException(MSG.AUTH_TOP_SUCCESS);
        }
    }

    //拒绝连麦
    @Override
    public boolean refuseTop(String userId, String mtId, boolean mastCompere) {
        //必须是房主操作
        if (mastCompere) mastMtCompere(mtId);

        //拒绝连麦，重置字段
        MtRoomUserAuth roomUserAuth = new MtRoomUserAuth();
        roomUserAuth.setAuthTop("0");
        roomUserAuth.setApplyTopStatus("0");

        QueryWrapper wrapper = QueryWrapper.create().and(MT_ROOM_USER_AUTH.USER_ID.eq(userId)).and(MT_ROOM_USER_AUTH.MT_ID.eq(mtId));

        int i = roomUserAuthMapper.updateByQuery(roomUserAuth, wrapper);

        return true;
    }

    //当前会议中上麦人员信息列表
    @Override
    public List<MtRoomUserAuth> topList(String mtId) {
        AuthKit.mastLogin();

        QueryWrapper wrapper = QueryWrapper.create().and(MT_ROOM_USER_AUTH.MT_ID.eq(mtId)).and(MT_ROOM_USER_AUTH.AUTH_TOP.eq("1"));

        return roomUserAuthMapper.selectListByQuery(wrapper);
    }

    //我的权限信息
    @Override
    public MtRoomUserAuth myAuth(String mtId) {
        AuthUser authUser = AuthKit.mastLogin();

        return roomUserAuthMapper.getByMtIdAndUserId(mtId, authUser.getUserId());
    }

    //踢出会议/允许参会
    @Override
    public boolean updateMtUserInOut(String userId, String mtId, String type) {
        mastMtCompere(mtId);

        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();

        //进入会议资格；0=正常；1=已被踢出会议；默认为0；
        //        1 踢出
        if ("1".equals(type)) mtRoomUserAuth.setIsOut("1");
        //        0 允许参会
        if ("0".equals(type)) mtRoomUserAuth.setIsOut("0");

        roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, userId);

        //通知用户已被踢出
        if ("1".equals(type)) wsOutUserMsg(mtId, userId);

        return true;
    }

    //允许发言/禁止发言
    @Override
    public boolean updateMtUserMsg(String userId, String mtId, String type) {
        mastMtCompere(mtId);

        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
        //发言资格；0=无资格；1=有资格；默认为1
        // 0 禁言
        if ("0".equals(type)) mtRoomUserAuth.setAuthMsg("0");
        //1 解除禁言
        if ("1".equals(type)) mtRoomUserAuth.setAuthMsg("1");

        roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, userId);

        //通知用户禁言状态改变
        wsUserMsgStatus(mtId, userId, type);

        return true;
    }

    //全局禁言/允许发言
    @Override
    public boolean updateAllAccessMsg(String mtId, String type) {
        mastMtCompere(mtId);
        MtRoom mtRoom = new MtRoom();
        mtRoom.setId(mtId);

        //    发消息状态；0=允许发言；1=全员禁言；默认为0；
        //        1 全体禁言
        if ("1".equals(type)) mtRoom.setMsgAuth("1");
        //        0 解除全体禁言
        if ("0".equals(type)) mtRoom.setMsgAuth("0");

        mtRoomMapper.update(mtRoom);

        //通知房间禁言状态改变
        wsRoomMsgStatus(mtId, type);

        return true;
    }

    //修改自己会议内的昵称
    @Override
    public void updateNickName(String mtId, String nickName) {
        AuthUser authUser = AuthKit.mastLogin();
        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
        mtRoomUserAuth.setMtNickName(nickName);
        roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, authUser.getUserId());
    }

    @Valid
    @Override
    public boolean updateRoomTitle(String mtId, @Length(min = 3, max = 8, msg = "会议标题长度为3-8个字符") String title) {
        mastMtCompere(mtId);
        MtRoom mtRoom = new MtRoom();
        mtRoom.setTitle(title);
        mtRoom.setId(mtId);
        mtRoomMapper.update(mtRoom);

        //更新房间信息
        wsRefreshRoomInfo(mtId);
        return false;
    }

    //修改我在会议内容的昵称
    @Valid
    @Override
    public boolean updateMyNickName(String mtId, @Length(min = 2, max = 8, msg = "昵称长度为2-8个字符") String nickName) {
        AuthUser authUser = AuthKit.mastLogin();
        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
        mtRoomUserAuth.setMtNickName(nickName);
        roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, authUser.getUserId());

        //刷新会议页面用户UI列表
        wsRefreshTopList(mtId);

        return true;
    }

    //修改我在会议内容的头像
    @Valid
    @Override
    public boolean updateMyNickAvatar(String mtId, @NotBlank String nickAvatar) {
        AuthUser authUser = AuthKit.mastLogin();
        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
        mtRoomUserAuth.setMtNickAvatar(nickAvatar.trim());
        roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, authUser.getUserId());

        //刷新会议页面用户UI列表
        wsRefreshTopList(mtId);
        return true;
    }

    /**
     * 修改会议内麦克风状态
     *
     * @param status 1=开麦 0=关麦
     */
    @Override
    public boolean updateMyAudio(String mtId, String status) {
        AuthUser authUser = AuthKit.mastLogin();
        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
        mtRoomUserAuth.setAudioStatus(status);
        roomUserAuthMapper.updateByMtIdUserId(mtRoomUserAuth, mtId, authUser.getUserId());

        //通知刷新当前用户列表
        wsRefreshTopList(mtId);

        return true;
    }

    //点赞
    @Valid
    @Override
    public void zan(@NotBlank String mtId) {
        AuthUser authUser = AuthKit.mastLogin();

        //追加房间热度和点赞数
        ThreadKit.getPool().execute(() -> {
            mtRoomMapper.addHotZan(mtId, 1, 1);
        });

        //发送用户点赞信息
        wsZan(mtId, authUser.getUserId());
    }

    //用户主动退出连麦
    @Valid
    @Override
    public void outMyTop(@NotBlank String mtId) {
        AuthUser authUser = AuthKit.mastLogin();
        boolean b = refuseTop(authUser.getUserId(), mtId, false);
        if (b) {
            //通知用户下麦
            wsUserTopStatus(mtId, authUser.getUserId(), "0");
            //通知所有人，有人下麦
            wsRefreshTopList(mtId);
        }
    }

    //根据完整的用户信息，关闭用户存在的会议
    @Override
    public boolean closeMtRoomByUser(SysUser sysUser, RedisMsgType redisMsgType) {
        //关闭权限
        sysUser.setMtAuthCloseTime(null);
        sysUser.setMtAuth("0");
        sysUserMapper.update(sysUser, false);

        //关闭会议室
        QueryWrapper eq = QueryWrapper.create().eq("user_id", sysUser.getId()).eq("meeting_status", "0");
        MtRoom mtRoom = mtRoomMapper.selectOneByQuery(eq);
        if (mtRoom != null) {
            mtRoom.setMeetingStatus("1");
            mtRoomMapper.update(mtRoom);
            //通知房间所有人，会议已关闭
            RedisMsgKit.sendMsg(redisMsgType, "{\"mtId\":\"" + mtRoom.getId() + "\"}");
        }
        return true;
    }

    /**
     * 检查必须是主持人才能操作
     */
    private MtRoomUserAuth mastMtCompere(String mtId) {
        AuthUser authUser = AuthKit.mastLogin();
        MtRoomUserAuth roomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, authUser.getUserId());
        //非主持人无权操作
        if (!"1".equals(roomUserAuth.getIsCompere())) throw new ServiceException(MSG.ER_403);
        return roomUserAuth;
    }

    /**
     * 当前登录人是否为该房间的主持人
     */
    private boolean isMtCompere(String mtId) {
        try {
            mastMtCompere(mtId);
            return true;
        } catch (Exception ignore) {
            return false;
        }
    }

    //异步更新用户退出会议记录
    private void saveOutLog(String mtId, String userId) {
        //更新退出记录
        MtRoomInOut roomInOut = new MtRoomInOut();
        roomInOut.setMtRoomId(mtId);
        roomInOut.setUserId(userId);
        roomInOut.setOutTime(LocalDateTime.now());
        inOutMapper.updateByQuery(roomInOut, QueryWrapper.create().and(MT_ROOM_IN_OUT.USER_ID.eq(userId)).and(MT_ROOM_IN_OUT.MT_ROOM_ID.eq(mtId)).and(MT_ROOM_IN_OUT.OUT_TIME.isNull()));

        //通知房间内人员，信息变动
        wsRefreshRoomInfo(mtId);
    }

    //添加上麦用户前，必须检查是否满足限制
    private void addBeforeCheckMaxTopUser(String mtId) {
        //查询当前上麦人数
        long nowTopCount = roomUserAuthMapper.selectCountByQuery(QueryWrapper.create().and(MT_ROOM_USER_AUTH.MT_ID.eq(mtId)).and(MT_ROOM_USER_AUTH.AUTH_TOP.eq("1")));
        MtRoom mtRoom = mtRoomMapper.selectOneById(mtId);
        String maxTopCount = mtRoom.getMaxTopCount();
        if (nowTopCount + 1 > Integer.parseInt(maxTopCount)) {
            throw new ServiceException(MSG.AUTH_TOP_IS_MAX);
        }
    }

    //通知房主有人申请上麦
    @Override
    public void wsApplyTopMsg(String applyUserId, String mtId) {
        ThreadKit.getPool().execute(() -> {
            String userId = mtRoomMapper.getMtUserId(mtId);
            MtRoomUserAuth byMtIdAndUserId = roomUserAuthMapper.getByMtIdAndUserId(mtId, applyUserId);
            String mtNickAvatar = byMtIdAndUserId.getMtNickAvatar();
            String mtNickName = byMtIdAndUserId.getMtNickName();

            JSONObject data = new JSONObject();
            data.put("userId", applyUserId);
            data.put("mtNickAvatar", mtNickAvatar);
            data.put("mtNickName", mtNickName);
            data.put("time", LocalDateTime.now());
            data.put("msg", "已发起连麦申请");
            data.put("showTime", 9000);

            SRS<Object> msgBody = SRS.bySuccess(data);
            msgBody.set("action", "applyTop");
            msgBody.set("mtId", mtId);

            //通知房主
            wsSendMtUser(userId, msgBody);
        });

    }

    //通知房间连麦人数变更
    @Override
    public void wsRefreshTopList(String mtId) {
        List<MtRoomUserAuth> mtRoomUserAuths = topList(mtId);

        ThreadKit.getPool().execute(() -> {
            //消息体
            SRS<Object> msgBody = SRS.bySuccess(mtRoomUserAuths);
            msgBody.set("action", "refreshTopList");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);

        });
    }

    //通知房间输入变动
    @Override
    public void wsSearchRoomUser(String mtId) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess();
            msgBody.set("action", "searchRoomUser");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);
        });
    }

    //通知房间信息变动
    @Override
    public void wsRefreshRoomInfo(String mtId) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess();
            msgBody.set("action", "refreshRoomInfo");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);
        });
    }

    //通知房间已经关闭
    @Override
    public void wsMtRoomClose(String mtId) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess();
            msgBody.set("action", "mtRoomClose");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);
        });
    }

    /**
     * 通知房间内所有人
     *
     * @param mtId             会议ID
     * @param sendUserId       发送人ID；传0为系统用户
     * @param sendMsg          发送消息
     * @param msgShowTimeMilli 消息显示时间；前端页面显示的时间
     */
    @Override
    public void wsMtRoomMsg(String mtId, String sendUserId, String sendMsg, Integer msgShowTimeMilli) {
        SysUser sysUser = sysUserMapper.selectOneById(sendUserId);
        MtRoomUserAuth mtRoomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, sendUserId);
        String mtNickAvatar = mtRoomUserAuth.getMtNickAvatar();
        String mtNickName = mtRoomUserAuth.getMtNickName();

        ThreadKit.getPool().execute(() -> {
            //保存消息
            MtRoomMsg mtRoomMsg = new MtRoomMsg();
            mtRoomMsg.setId(IdKit.getId());
            mtRoomMsg.setRoomId(mtId);
            mtRoomMsg.setUserId(sendUserId);
            mtRoomMsg.setContent(sendMsg);
            mtRoomMsgMapper.insertSelective(mtRoomMsg);

            JSONObject jsonObject = new JSONObject();

            if (sysUser == null) {
                jsonObject.put("userId", "0");
                jsonObject.put("nickName", "系统提示");
                jsonObject.put("mtNickName", "系统提示");
                jsonObject.put("mtNickAvatar", mtNickAvatar);
                jsonObject.put("account", "0");
            } else {
                jsonObject.put("mtNickName", mtNickName);
                jsonObject.put("mtNickAvatar", mtNickAvatar);
                jsonObject.put("account", sysUser.getAccount());
                jsonObject.put("msgId", mtRoomMsg.getId());
                jsonObject.put("userId", sysUser.getId());

            }

            jsonObject.put("time", LocalDateTime.now());
            jsonObject.put("msg", sendMsg);
            jsonObject.put("showTime", msgShowTimeMilli);

            SRS<Object> msgBody = SRS.bySuccess(jsonObject);
            msgBody.set("action", "sendMsg");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);

        });
    }

    /**
     * 通知房间有人点赞
     */
    private void wsZan(String mtId, String sendUserId) {
        ThreadKit.getPool().execute(() -> {
            String sendMsg = "❤赞❤赞❤";
            int msgShowTimeMilli = 1300;

            MtRoomUserAuth mtRoomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtId, sendUserId);
            String mtNickAvatar = mtRoomUserAuth.getMtNickAvatar();
            String mtNickName = mtRoomUserAuth.getMtNickName();

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("mtNickName", mtNickName);
            jsonObject.put("mtNickAvatar", mtNickAvatar);
            jsonObject.put("time", LocalDateTime.now());
            jsonObject.put("msg", sendMsg);
            jsonObject.put("showTime", msgShowTimeMilli);

            SRS<Object> msgBody = SRS.bySuccess(jsonObject);
            msgBody.set("action", "sendMsg");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);
        });
    }

    //通知用户被踢出房间
    @Override
    public void wsOutUserMsg(String mtId, String outUserId) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess(outUserId);
            msgBody.set("action", "outUser");
            msgBody.set("mtId", mtId);

            //通知用户本人
            wsSendMtUser(outUserId, msgBody);
        });
    }

    //通知:刷新我在房间内的信息
    @Override
    public void wsRefreshMyInfo(String mtId, String userId) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess();
            msgBody.set("action", "refreshMyInfo");
            msgBody.set("mtId", mtId);

            //通知用户本人
            wsSendMtUser(userId, msgBody);
        });
    }

    //通知用户上麦状态
    @Override
    public void wsUserTopStatus(String mtId, String userId, String status) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess(status);
            msgBody.set("action", "userTopStatus");
            msgBody.set("mtId", mtId);
            //通知用户本人
            wsSendMtUser(userId, msgBody);
        });
    }

    //通知用户禁言状态
    public void wsUserMsgStatus(String mtId, String userId, String status) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess(status);
            msgBody.set("action", "userMsgStatus");
            msgBody.set("mtId", mtId);

            //通知用户本人
            wsSendMtUser(userId, msgBody);
        });
    }

    //通知房间禁言
    public void wsRoomMsgStatus(String mtId, String status) {
        ThreadKit.getPool().execute(() -> {
            SRS<Object> msgBody = SRS.bySuccess(status);
            msgBody.set("action", "roomMsgStatus");
            msgBody.set("mtId", mtId);

            //房间内所有人通知
            wsSendMtAll(mtId, msgBody);

        });
    }

    //发出通知
    public void wsSendMtAll(String mtId, SRS<Object> msgBody) {
        msgBody.set("wsPushType", WsPushType.MT_LIVE);
        List<String> userIds = roomUserAuthMapper.getNowUserIds(mtId);
        for (String userId : userIds) {
            Channel channel = TextHandler.channelPhoneAll.get("PHONE" + userId);
            channel.writeAndFlush(new TextWebSocketFrame(msgBody.toJSONString()));
        }
    }

    //发出通知
    public void wsSendMtUser(String userId, SRS<Object> msgBody) {
        msgBody.set("wsPushType", WsPushType.MT_LIVE);
        Channel channel = TextHandler.channelPhoneAll.get("PHONE" + userId);
        channel.writeAndFlush(new TextWebSocketFrame(msgBody.toJSONString()));
    }

}
